/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mujmail;

import javax.microedition.location.Location;
import lcduilwuit.Form;
import lcduilwuit.Command;
import javax.microedition.media.control.*;
import javax.microedition.media.*;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.MediaComponent;
import com.sun.lwuit.Image;
import com.sun.lwuit.TextArea;
import com.sun.lwuit.plaf.Border;
import javax.microedition.io.file.*;
import javax.microedition.io.*;
import java.io.*;

import com.sun.lwuit.Dialog;
import com.sun.lwuit.Label;
import com.sun.lwuit.Component;
import com.sun.lwuit.util.Resources;
import com.sun.lwuit.layouts.BorderLayout;
import org.apache.sanselan.formats.tiff.*;
import org.apache.sanselan.formats.jpeg.exifRewrite.*;
import org.apache.sanselan.formats.tiff.write.*;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.common.*;
import org.apache.sanselan.formats.jpeg.*;

import javax.microedition.location.LocationProvider;
import javax.microedition.location.LocationListener;
import javax.microedition.location.LocationException;
import javax.microedition.location.QualifiedCoordinates;
/*
 * @author anup.s
 */

public class SnapshotForm extends Form implements ActionListener {

    MediaComponent medComponent;
    Player player;
    VideoControl videoControl;
    Command captureSnap = new Command("Capture");
    Command cancelSnap = new Command("Cancel");
    Command discardSnap = new Command("Discard");
    Command attachSnap = new Command("Attach");
    byte[] rawImage;
    Form prevScreen;
    private SendMail sndMail;
    private final String SNAPSHOT_LOCATION = MujMail.mujmail.getAppProperty("SNAPSHOT-LOCATION");
    private boolean gpsCancelled;

    public SnapshotForm(Form scr, SendMail sndmail) {
        super("Take a picture");
        sndMail = sndmail;
        setScrollable(false);
        prevScreen = scr;
        if (Settings.enableGeotagging) {
            try {

                GPSStuff.getInstance();
                if (!Settings.startGPSinit) {
                    GPSStuff.shutDownWhenNoNeed(true);
                }
                if (!GPSStuff.getInstance().isGPSAvailable()) {

                    final Dialog gpsDialog = new Dialog();
                    gpsDialog.setLayout(new BorderLayout());
                    gpsDialog.addComponent(BorderLayout.NORTH, new Label("Getting GPS...."));
                    Image loadImg = null;
                    try {
                        loadImg = Resources.open("/load.res").getImage("loading");

                    } catch (IOException ioe) {
                        //ignore
                    }
                    final Label loading = new Label(loadImg);
                    loading.setAlignment(Component.CENTER);
                    gpsDialog.addComponent(BorderLayout.CENTER, loading);
                    TextArea txt = new TextArea("Cancel to    proceed without geotagging.", 4, 2, com.sun.lwuit.TextArea.UNEDITABLE);
                    txt.getStyle().setBorder(Border.createEmpty());
                    txt.setFocusable(false);
                    txt.getStyle().setFgColor(getStyle().getFgColor());
                    gpsDialog.addComponent(BorderLayout.SOUTH, txt);
                    gpsDialog.addCommand(new Command("Cancel") {

                        public void actionPerformed(ActionEvent evt) {
                            gpsCancelled = true;
                            gpsDialog.dispose();
                        }
                    });
                    GPSStuff.getInstance().setGPSCallBack(new GPSStuff.GPSCallBack() {

                        public void callBack(int state) {
                            if (state == LocationProvider.AVAILABLE) {
                                gpsDialog.dispose();
                            } else if (state == LocationProvider.OUT_OF_SERVICE) {
                                gpsCancelled = true;
                                gpsDialog.replace(loading, new Label("GPS is out of service"), null);
                            }
                        }
                    });

                    gpsDialog.show();
                }
            } catch (SecurityException se) {
                com.sun.lwuit.Dialog.show("Exception", "Couldnt start GPS, Please give permission", "OK", "");
            } catch (Exception le) {
                com.sun.lwuit.Dialog.show("Exception", "Couldnt start GPS: " + le, "OK", "");
            }
        }
        startCamera();
    }

    private void startCamera() {

        addCommand(cancelSnap);
        addCommand(captureSnap);
        setCommandListener(this);
        new Thread() {

            public void run() {
                try {
                    Thread.sleep(100);
                    player = Manager.createPlayer("capture://video");
                    player.realize();
                    videoControl = (VideoControl) player.getControl("VideoControl");
                    medComponent = new MediaComponent(player);
                    player.start();
                    addComponent(medComponent);
                } catch (Exception e) {
                    if (player != null) {
                        player.close();
                    }
                    player = null;
                    e.printStackTrace();
                }
            }
        }.start();


    }

    private void close() {
        if (player != null) {
            player.close();
        }
        player = null;
        videoControl = null;
        removeComponent(medComponent);
        System.gc();
    }

    private byte[] captureSnap() {
        byte[] raw = null;
        try {
            raw = videoControl.getSnapshot(null);//"encoding=jpeg&width=176&height=220");
        } catch (Exception me) {
            me.printStackTrace();
        }
        close();
        return raw;
    }

    private void getAndAddExif(final byte[] data, final OutputStream os) throws IOException{
        if (!gpsCancelled && Settings.enableGeotagging) {
            try {

                addExif(data, os, GPSStuff.getInstance().getLongi(), GPSStuff.getInstance().getLati());
            } catch (SecurityException se) {
                com.sun.lwuit.Dialog.show("Exception", "Couldnt start GPS, Please give permission", "OK", "");
            } catch (Exception le) {
                com.sun.lwuit.Dialog.show("Exception", "Couldnt start GPS: " + le, "OK", "");
            }
        }else{
            os.write(data);
        }
        /* try {
        final Dialog gpsDialog = new Dialog("GPS");
        gpsDialog.addComponent(new Label("Getting GPS...."));
        gpsDialog.addCommand(new Command("Cancel") {

        public void actionPerformed(ActionEvent evt) {
        gpsDialog.dispose();
        }
        });

        LocationProvider lp = LocationProvider.getInstance(null);
        LocationListener locL = new LocationListener() {

        public void locationUpdated(LocationProvider lp, Location lctn) {
        if (lp.getState() == LocationProvider.AVAILABLE) {
        QualifiedCoordinates qc = lctn.getQualifiedCoordinates();
        addExif(data, os, qc.getLongitude(), qc.getLatitude());
        gpsDialog.dispose();
        }
        }

        public void providerStateChanged(LocationProvider lp, int i) {
        switch (i) {
        case LocationProvider.AVAILABLE:
        break;
        case LocationProvider.TEMPORARILY_UNAVAILABLE:

        break;
        case LocationProvider.OUT_OF_SERVICE:
        gpsDialog.addComponent(new Label("GPS is out of service."));
        break;
        default:

        }
        }
        };
        lp.setLocationListener(locL, -1, -1, -1);
        gpsDialog.show();

        } catch (LocationException le) {
        Dialog.show("Exception", "LocationException:" + le.getMessage() == null ? "" : le.getMessage(), "OK", "Cancel");

        } catch (SecurityException le) {
        Dialog.show("Exception", "SecurityException: Please give permisiion to get location.", "OK", "Cancel");
        }*/
    }

    private void addExif(byte[] data, OutputStream os, double longi, double lati) {
        IImageMetadata metadata = null;
        JpegImageMetadata jpegMetadata = null;
        TiffImageMetadata exif = null;
        TiffOutputSet outputSet = new TiffOutputSet();
        byte[] oldData = new byte[data.length];
        System.arraycopy(data, 0, oldData, 0, data.length);
        // establish metadata
        try {

            metadata = Sanselan.getMetadata(data);
            data = null;

        } catch (ImageReadException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // establish jpegMedatadata
        if (metadata != null) {
            jpegMetadata = (JpegImageMetadata) metadata;
        }

        // establish exif
        if (jpegMetadata != null) {
            exif = jpegMetadata.getExif();
        }

        // establish outputSet
        if (exif != null) {
            try {
                outputSet = exif.getOutputSet();
            } catch (ImageWriteException e) {
            }
        }
        try {
//outputSet.getExifDirectory().
            outputSet.setGPSInDegrees(longi, lati);

            //GPSStuff.setGPS(12.966667, 77.566667, 950, outputSet);
        } catch (ImageWriteException e) {
        }

        try {


            new ExifRewriter().updateExifMetadataLossless(oldData,
                    os, outputSet);
        } catch (ImageReadException e) {
            e.printStackTrace();
        } catch (ImageWriteException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Throwable t) {
            t.printStackTrace();
        } finally {
        }


    }

    private String writeToFile(byte[] data) {
        int trial = 0;
        FileConnection fc = null;
        OutputStream os = null;
        String url = "";
        while (true) {
            try {
                fc = (FileConnection) Connector.open(SNAPSHOT_LOCATION + "SonimMail_Captured_" + (trial++) + ".jpg");
                if (!fc.exists()) {
                    url = fc.getURL();
                    fc.create();
                    System.out.println("URL=" + url);
                    break;
                } else {
                    fc.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        try {
            os = fc.openOutputStream();
            if (Settings.enableGeotagging) {
                getAndAddExif(data, os);
            }else{
            os.write(data);
            }
            os.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (Exception ignored) {
            }
            try {
                fc.close();
            } catch (Exception ignored) {
            }
        }
        return url;
    }

    public void actionPerformed(ActionEvent arg0) {
        com.sun.lwuit.Command cmd = arg0.getCommand();
        if (cmd == cancelSnap) {
            close();
            prevScreen.show();
        } else if (cmd == captureSnap) {
            if (mujmail.ui.AudioAlert.player != null)// && !mujmail.ui.AudioAlert.player.equals(PlayerListener.CLOSED))
            {
                return;
            }//
            try {
                rawImage = captureSnap();
                byte[] thumb = null;

                thumb = getThumbJpeg(rawImage);
                addComponent(new com.sun.lwuit.Label(com.sun.lwuit.Image.createImage(thumb, 0, thumb.length)));
                removeAllCommands();
                addCommand(discardSnap);
                addCommand(attachSnap);
            } catch (Throwable t) {
                rawImage = null;
                removeAll();
                removeAllCommands();
                startCamera();
                System.gc();
            }
        } else if (cmd == discardSnap) {
            rawImage = null;
            removeAll();
            removeAllCommands();
            startCamera();
            System.gc();
        } else if (cmd == attachSnap) {
            String filePath = writeToFile(rawImage);
            int size = rawImage.length;
            BodyPart bp = new BodyPart(new MessageHeader(sndMail.mujMail.outBox), filePath,
                    filePath.substring(filePath.lastIndexOf('/') + 1), filePath.substring(filePath.lastIndexOf('/') + 1), size);

            //   BodyPart bp = new BodyPart(new MessageHeader(mujMail.outBox), "captured_image_"+(captureCount++)+".jpg",rawImage);

            if (sndMail.getAttachementsAdder().getTotalAttachmentSize() + size > Settings.MAX_ATTACHMENT_SIZE_FOR_SENDING) {
                lcduilwuit.Alert alrt = new lcduilwuit.Alert("ERROR!!!");
                alrt.setString(Lang.get(Lang.EXTRA_TOTAL_ATTCHMENT_SIZE) + " > " + (Settings.MAX_ATTACHMENT_SIZE_FOR_SENDING / 1000) + "KB");
                MujMail.mujmail.getDisplay().setCurrent(alrt);
                return;
            } else {
                sndMail.getAttachementsAdder().addAttachment(bp);

                // find file size
                //((FSStorage) bp.getStorage()).updateSizeInNewThread(new UpdateAttachmentSizeCallback(sendMail, bp));
            }



            if (prevScreen instanceof LwuitUI.Menu) {
                sndMail.initSendSnap();
                sndMail.writeMail(prevScreen);
            } else {
                prevScreen.show();
            }
        }

    }

    public static byte[] getThumbJpeg(byte[] fileBytes) {


        try {
// Open file and stream
// Create a byte array to hold file contents
// If file is JPEG encoded.
            if ((fileBytes[0] & 0xFF) == 0xFF && (fileBytes[1] & 0xFF) == 0xD8) {
// if a thumbnail is not found throw Exception
                int startIndex = 2;
                do {

//All JPEG markers begin with 0xFF
                    while (fileBytes[startIndex] != -1) {
                        startIndex++;

                    }
                    startIndex++;
// Try to find another Start Of Image marker (FFD8)
                } while ((fileBytes[startIndex] & 0xFF) != 0xD8);

                int endIndex = startIndex + 1;
                do {
// -1 == 0xFF and all JPEG markers begin with 0xFF
                    while (fileBytes[endIndex] != -1) {
                        endIndex++;
                    }
                    endIndex++;
                    if ((fileBytes[endIndex] & 0xFF) == 0xA0) {
                        endIndex++;
                        if ((fileBytes[endIndex] & 0xFF) == 0x02) {
                            System.out.println("found 2");
                            System.out.println(fileBytes[endIndex++]);
                        }
                    }
// Now try to find the End Of Image marker (FFD9).
                } while ((fileBytes[endIndex] & 0xFF) != 0xD9);
// Create image out of thumbnail.
                System.out.println("try thumb create");


                byte ee[] = new byte[endIndex - startIndex + 2 /*- (startIndex - 1)*/];
                System.arraycopy(fileBytes, startIndex - 1, ee, 0, ee.length);
                fileBytes = null;

                return ee;


            }

        } catch (Throwable e) {
            if (e instanceof OutOfMemoryError) {
                System.gc();
                System.gc();
            }

            System.out.println("No Thumb found.. "
                    + " " + e.toString());
        } finally {
// TODO: handle exception
        }

        return null;
    }
}
